/*
Soot:
    Soot 是一个用于分析、优化和可视化 Java 程序的开源工具包。
    它提供了一个丰富的 API 和一套功能强大的工具，使得研究人员和开发者能够在静态和动态层面对 Java 代码进行深入的分析。
    1. 静态分析： Soot 主要用于静态分析，即在程序运行之前分析代码。它可以生成控制流图、数据流图和其他高级的程序表示，以便分析程序结构和行为。
    2. 字节码分析： Soot 可以直接处理 Java 字节码，这使得它能够在不依赖源代码的情况下进行分析。这对于那些无法获取源代码或需要在编译前进行分析的场景非常有用。
    3. 可视化： Soot 不仅可以生成程序的中间表示，还可以通过图形化工具进行可视化，帮助用户更好地理解和分析代码结构。
    4. 插件系统： Soot 提供了一个灵活的插件系统，使得用户可以编写自定义的分析和转换插件，以适应特定的需求和场景。
 */

package jtg.graphics;

import soot.*;
import soot.jimple.JimpleBody;
import soot.options.Options;
import soot.toolkits.graph.BlockGraph;
import soot.toolkits.graph.BriefBlockGraph;
import soot.toolkits.graph.ClassicCompleteUnitGraph;
import soot.toolkits.graph.UnitGraph;

import java.io.File;

// 类SootCFG==>使用了Soot工具包来进行静态分析
// 类SootCFG实现功能：获取指定方法的控制流图 CFG
public class SootCFG {


    // input ==> 源代码目录路径、类名、方法名
    // output ==> 方法的控制流图CFG
    public static UnitGraph getMethodCFG(String sourceDirectory,String clsName,String methodName){
        // sourceDirectory:源代码目录路径
        // clsName:类名
        // methodName:方法名

        // 调用‘getMethodBody’方法获取给定类和方法体('Body'对象)
        Body body = getMethodBody(sourceDirectory,clsName,methodName);

        // 利用 ClassicCompleteUnitGraph 类构建该方法体的控制流图（CFG）
        // ClassicCompleteUnitGraph ==> soot包提供
        UnitGraph ug = new ClassicCompleteUnitGraph(body);
        return ug;
    }


    public static BlockGraph getSimpleCFG(Body body){
//        Body body = getMethodBody(sourceDirectory,clsName,methodName);
        BlockGraph bg = new BriefBlockGraph(body);
        return bg;
    }
    // input => 源代码文件路径、类名、方法名
    // output => 方法体（body 对象）
    public static Body getMethodBody(String sourceDirectory,String clsName,String methodName){
        // 调用 G.reset() 方法来重置 Soot 工具。
        G.reset();

        // 设置一些 Soot 工具的选项
        Options.v().set_prepend_classpath(true); // 类路径添加到前缀
        Options.v().set_allow_phantom_refs(true); // 允许虚拟引用

        Options.v().set_keep_line_number(true);
        Options.v().set_keep_offset(true);
        Options.v().set_soot_classpath(sourceDirectory); // 设置 Soot 类路径

        // 加载指定类，并将其标记为应用程序类。
        SootClass sc = Scene.v().loadClassAndSupport(clsName);
        sc.setApplicationClass();

        Scene.v().loadNecessaryClasses(); // 加载必要的类。
        SootClass mainClass = Scene.v().getSootClass(clsName); // 根据类名获取指定类
        SootMethod sm = mainClass.getMethodByName(methodName); // 根据方法名获取对应的方法
        Body body = sm.retrieveActiveBody(); // 获取方法体（Body 对象）。
        return body;
    }
    public static Body getMethodBody(String clsName,String signature){
        G.reset();
        Options.v().set_prepend_classpath(true);
        Options.v().set_allow_phantom_refs(true);
        Options.v().set_soot_classpath(System.getProperty("user.dir") + File.separator + "target" + File.separator + "test-classes");
        SootClass sc = Scene.v().loadClassAndSupport(clsName);
        sc.setApplicationClass();
        Scene.v().loadNecessaryClasses();
        SootMethod sm = Scene.v().getMethod(signature);
        Body body = sm.retrieveActiveBody();
        return body;
    }
}
